閉包無所不在,在你還沒知覺到的時候,你已經寫了一個閉包,像是這樣:
const outVar = "out variable";
const displayVar = function () {
  console.log(outVar);
};
displayVar();
所以閉包在哪裡?閉包到底是什麼?
也許有人會說,騙人這哪有閉包,這就scope chain啊,沒錯!這是scope chain,但!也是閉包!(忍者說的,請參閱v2 p104)。
因為outVar和displayVar都在全域宣告,所以只要程式還在執行,scope就不會消失,看起來好像不是閉包,所以這也是為什麼要把閉包和他的小夥伴scope chain一起寫的原因。
像是這樣:
呼叫outer()時,會先執行黃色框內的code,其中定義了變數outerVar和函式innerFn(),並呼叫innerFn(),此時會執行紅色框,發現紅框內找不到outerVar,往外層有找到,可印出outerVar字串

const delayText = function () {
  const text = "this is a delay message";
  setTimeout(() => console.log(text), 2000);
};
delayText();
function countDogs() {
  let dogNum = 0;
  return function () {
    dogNum++;
    console.log(`${dogNum} dog(s)`);
  };
}
const myFunc = countDogs();
myFunc(); //1 dog(s)
myFunc(); //2 dog(s)
myFunc(); //3 dog(s)
 
const outerFn = function () {
  const outerVar = "I am from outer function";
  const innerFn = function () {
    console.log(outerVar);
  };
  return innerFn;
};
const myClosure = outerFn();
myClosure(); //  I am from outer function
事情是這樣發生的:
我們把outerFn裡本來直接執行的innerFn改成傳出來,並存在另一個變數myClosure,當執行myClosure時,當初宣告innerFn的outerFn已經執行完,它的execution context早就消失了,但因為閉包的特性,innerFn還是可以從當初宣告的位置,依循scope chain找到需要的outerVar印出來

function pushFunc() {
  var arr = [];
  for (var i = 0; i < 3; i++) {
    arr.push(function () {
      console.log(i);
    });
  }
  return arr;
}
var resultArr = pushFunc(); 
resultArr[0]();
resultArr[1]();
resultArr[2]();
function pushFunc() {
  var arr = [];
  for (let i = 0; i < 3; i++) {
    arr.push(function () {
      console.log(i);
    });
  }
  return arr;
}
var resultArr = pushFunc(); 
resultArr[0]();
resultArr[1]();
resultArr[2]();
第一題答案是3 3 3,第二題答案是0 1 2。
主要差別在於for迴圈裡,變數i的宣告方式,第一題是用var;第二題是用let。
console.log(functionArr[0]); 
//ƒ () {
//      console.log(i);
//    }
 所以每個匿名函式透過閉包找i值時,都會找到的是for迴圈跑完的時候,i=3的狀態。
所以每個匿名函式透過閉包找i值時,都會找到的是for迴圈跑完的時候,i=3的狀態。 每跑一圈就會抓到一個i。
每跑一圈就會抓到一個i。其實推幾次之後,好像會建立一種類直覺的感受,就可以比較快判斷出來了!tl;dr 閉包是一個包住函式定義與其scope chain的泡泡,它可以確保當函式執行時,無論當初的scope是否存在,都可以依循scope chain找到所需的變數。
ref
JS 原力覺醒 Day08 - Closures
所有的函式都是閉包:談 JS 中的作用域與 Closure